#include<iostream>
#include<vector>
#include<string>
#include <boost/filesystem.hpp>
#include "util.hpp"

const std::string src_path = "data/input";//保存源文件的路径
const std::string output = "data/raw_html/raw.txt";//源文件解析后的路径

typedef struct DocInfo
{
    std::string titel;
    std::string content;
    std::string url;
}DocInfo_t;


// const &:输入
// *：输出
// &：输入输出

//函数声明
bool EnumFile(const std::string& src_path, std::vector<std::string>* file_list);
bool ParserHtml(const std::vector<std::string> &file_list, std::vector<DocInfo_t>* result);
bool SaveHtml(const std::vector<DocInfo_t>& result,const std::string&  output);

int main()
{
    std::vector<std::string> file_list;
    // 第一步：递归式的把每个html文件名带路径，保存在file_list中。
    if(!EnumFile(src_path, &file_list))
    {
        std::cerr << "enum file name error" << std::endl;
        return 1;
    }

    std::vector<DocInfo_t> result;
    // 第二步：按照file_list中的html读取每个文件的内容，并对内容进行解析,对解析后的内容放在result中
    if(!ParserHtml(file_list, &result))
    {
        std::cerr << "parser html error"<< std::endl;
        return 2;
    }
    // 第三步：把解析完成的内容，写入到output中
    if(!SaveHtml(result, output))
    {
        std::cerr << "save html error " << std::endl;
        return 3;
    }
    return 0;
}

// 对函数的实现
bool EnumFile(const std::string& src_path, std::vector<std::string>* file_list)
{
    namespace fs = boost::filesystem;
    // 定义一个path对象
    fs::path root_path(src_path);
    // 判断路径对象是否存在
    if(!fs::exists(root_path))
    {
        std::cerr << "root_path unexists" << std::endl;
        return 1;
    }
    //定义一个空的迭代器对象
    fs::recursive_directory_iterator end;
    for(fs::recursive_directory_iterator iter(root_path); iter != end; iter++)
    {
        // 判断当前遍历的文件是否是一个普通文件
        if(!fs::is_regular_file(*iter))
            continue;
        // 判断普通文件是以.html结尾
        if(iter->path().extension() != ".html")
            continue;
        // 最后要使用string将path对象转换为字符串路径
        // 最后将合法路径保存在file_list
        // std::cout << "Debug: " << iter->path().string() << std::endl;

        file_list->push_back(iter->path().string());
    }
    return true;
    
}

//提取title
bool ParserTitle(std::string &result, std::string* title)
{
    ssize_t begin = result.find("<title>");
    if(begin == std::string::npos)
    {
        return false;
    }
    ssize_t end = result.find("</title>");
    if(end == std::string::npos)
    {
        return false;
    }
    begin += std::string("<title>").size();
    if(begin > end) return false;
    *title = result.substr(begin, end - begin);
    return true;
}
// 提取content
bool ParserContent(std::string &result, std::string* content)
{
    enum stat
    {
        LABLE,
        CONTENT
    };
    enum stat s = LABLE;
    for(char c : result)
    {
        switch (s)
        {
        case LABLE:
            if(c == '>') 
            {
                s = CONTENT;
            }
            break;
        case CONTENT:
            if(c == '<') s = LABLE;
            else
            {
                //我们不想保留原始文件中的\n,因为我们想用\n作为html解析之后文本的分隔符
                if(c == '\n') c = ' ';
                content->push_back(c);
            }
            break;
        default:
            break;
        }
    }
    return true;
}
// 构建url
bool ParserUrl(const std::string &file_path, std::string* url)
{
    std::string url_head = "https://www.boost.org/doc/libs/1_85_0/doc/html";
    std::string url_tail = file_path.substr(src_path.size());
    *url = url_head + url_tail;
    return true;
}

void ShowDoc(const DocInfo_t& doc)
{
    std::cout << "title:" << doc.titel << std::endl;
    std::cout << "content:" << doc.content << std::endl;
    std::cout << "url:" << doc.url << std::endl;
}

bool ParserHtml(const std::vector<std::string> &file_list, std::vector<DocInfo_t> *results)
{
    for(const std::string &file : file_list)
    {
        // 1.读文件
        std::string result;
        if(!ns_util::FlieUtil::ReadFlie(file, &result))
        {
            continue;
        }
        DocInfo_t doc;
        // 2.解析指定文件，提取title
        if(!ParserTitle(result, &doc.titel))
        {
            continue;
        }
        // 3.解析指定文件，提取content
        if(!ParserContent(result, &doc.content))
        {
            continue;
        }
        // 4.解析指定文件路径，构建url
        if(!ParserUrl(file, &doc.url))
        {
            continue;
        }
        //一个小的优化，如果直接push_back会发生拷贝，效率可能会低
        // 使用move可以减少拷贝，直接把doc move到results中
        results->push_back(std::move(doc));
        // 代码测试
        // sleep(2);
        // ShowDoc(doc);
        
    }
    return true;
}

bool SaveHtml(const std::vector<DocInfo_t>& result,const std::string& output)
{
    #define SEP '\3';
    //以二进制写入方式打开文件
    std::ofstream out(output, std::ios::out | std::ios::binary);
    if(!out.is_open())
    {
        std::cerr << "open" << output << "fail" << std::endl;
        return false;
    }

    //往文件中写入内容
    for(auto& item : result)
    {
        std::string out_string;
        out_string = item.titel;
        out_string += SEP;
        out_string += item.content;
        out_string += SEP;
        out_string += item.url;
        out_string += "\n";
        out.write(out_string.c_str(), out_string.size());
    }

    out.close();
    return true;
}